package characteristics.polymorphism;

import bean.Man;
import bean.Person;
import bean.Student;
import bean.Woman;
import org.junit.Test;

/**
 * 多态性
 * 1.理解为事物的多种形态。
 * 2.Java中多态性的体现与应用：
 * // 多态性的应用：虚拟方法调用
 * // 在多态的场景下，调用方法时：
 * // 编译时，认为方法是左边声明的父类的类型的方法（即被重写的方法）
 * // 执行时，实际执行的是子类重写父类的方法。
 * 3.多态性的使用前提：① 要有类的继承关系 ②要有方法的重写
 * 4.多态性的适用性：适用于方法，不适用于属性。
 * 5.多态的好处与弊端：
 * > 好处：
 * 开发中，
 * 使用父类做方法的形参，是多态使用最多的场合。
 * 即使增加了新的子类，方法也无需改变，提高了扩展性，符合开闭原则。
 * 极大减少了代码的冗余，不需要定义多个重载的方法。
 * <p>
 * 开闭原则OCP：
 * > 对扩展开放，对修改关闭
 * > 通俗解释：软件系统中的各种组件，如模块（Modules）、类（Class）以及功能（Functions）等，
 * 应该在不修改现有代码的基础上，引入新功能。
 * <p>
 * > 弊端：
 * eg:Person person1 = new Man();
 * 针对于创建的对象，在内存中是否加载了Man类中声明的特有的属性和方法？ 加载了！
 * 能不能直接调用Man中加载的特有的属性和方法呢？ 不能！
 * <p>
 * 在多态的场景下，创建了子类的对象，也加载了子类特有的属性和方法，
 * 但是由于声明为父类的引用，导致不能直接调用子类特有的属性和方法。
 */
public class PolymorphismTest {
    @Test
    public void testManAndWoman() {
        //多态性之前的场景
        Person person = new Person();
        Man man = new Man();

        // 多态性
        Person person1 = new Man();
        // 多态性的应用：虚拟方法调用
        // 在多态的场景下，调用方法时：
        // 编译时，认为方法是左边声明的父类的类型的方法（即被重写的方法）
        // 执行时，实际执行的是子类重写父类的方法。

        person1.eat();
        System.out.println(person1);

        System.out.println(person1.getName()); // Man
        System.out.println(person1.name); // Person

        System.out.println("---------------");
//        不能直接调用子类特有的结构
//        person1.earnMoney();
        // 向下转型
        Man man1 = (Man) person1;
        man1.earnMoney();
        System.out.println(person1 == person1); // true

        /**
         * 向下转型可能会出现：类型转换异常(ClassCastException)
         *
         * 1.建议在向下转型之前，使用instanceof进行判断，避免出现类型转换异常
         * 2.格式： a instanceof A: 判断对象a是否是类A的实例
         * 3.如果 a instanceof A 返回 true，则：
         *  a instanceof superA 返回也是 true。其中 A 是 superA 的子类。
         */
        Person person2 = new Woman();
//        Man man2 = (Man) person2;
//        man2.earnMoney();
        if (person2 instanceof Man) {
            Man man2 = (Man) person2;
            man2.earnMoney();
        }

    }

    @Test
    public void testHashCode() {
        Student student = new Student(1, 12, 99);
        Student student2 = new Student(1, 12, 99);
        System.out.println(student.hashCode() == student2.hashCode()); // true
        student2.setNumber(2);
        System.out.println(student.hashCode() == student2.hashCode()); // false
    }

    @Test
    public void testClo() {
        Person person = new Person();
//        person.clone
        StringBuffer s = new StringBuffer();

        String s1 = "str";
        String s2 = s1;
        s2 = "tt";
        System.out.println(s1);
        System.out.println(s2);

    }
}

